<!--
 * @Date: 2024-11-21 15:35:50
 * @Author: LiSong
 * @LastEditors: g05047
 * @LastEditTime: 2025-02-28 09:15:00
 * @Description: 饼状图
-->
<template>
  <div class="hp-chart-panel">
    <div class="hp-chart-panel-header">
      <div class="header-title">{{ schema.label }}</div>
      <div class="header-tools"></div>
    </div>
    <div class="hp-chart-panel-body"
      style="position: relative;">
      <div ref="chartRef"
        class="chart-warp"
        :id="schema.id"
        v-hpresize="chartsHook.resizeChart">
      </div>
      <div v-if="isEmptyData"
        style="position: absolute; top: 0; left:0; width: 100%; height: 100%; background-color: white;">
        <ElEmpty style="padding: 10px; height: 100%;"
          description="暂无数据"
          :image-size="60" />
      </div>
    </div>
  </div>
</template>

<script setup>
import { omit, debounce, } from 'lodash';
import { isEmpty } from '@hp/utils/data.js';
import * as echarts from 'echarts';
import { onMounted, ref, watch, nextTick, } from 'vue';
import { useDbSource } from '@hp/hooks/useDbSource.js'
import { commonProps } from '@hp/panels/cfg.js'
import { useCharts } from '@hp/hooks/useCharts.js'
import { useDbSourceStore } from '@hp/stores/store-dbsource.js'
import { usePie } from './hooks/usePie.js'
import { useTagsViewRoutes } from '@/stores/tagsViewRoutes';
import { useRouter } from 'vue-router';
import { useEventFunc } from '@hp/hooks/useEventFunc.js'


const router = useRouter();
const { tagsViewRoutes } = useTagsViewRoutes();
// 数据集
const dbSourceStore = useDbSourceStore()

const emits = defineEmits(['mounted'])
const props = defineProps({
  ...commonProps
})
// 事件函数相关操作
const eventFuncHook = useEventFunc({ ...props })
const { handleCreateTableData, handlePiePath, handlePieData } = usePie()
// 图例通用操作
const chartsHook = useCharts({ ...props })
// 数据源相关操作
const dbsourceHook = useDbSource({ ...props })
const { chartMod, chartRef } = chartsHook
// 默认展示数据
let options = {
  // legend: {
  //   orient: 'vertical',
  //   left: 'left',
  //   show: false,
  // },
  // tooltip: {
  //   trigger: 'item'
  // },
  // toolbox: {
  //   show: false
  // },
  // color: [],
  // series: [
  //   {
  //     name: 'Access From',
  //     type: 'pie',
  //     roseType: '',
  //     radius: [],
  //     center: [],
  //     data: [],
  //     emphasis: {
  //     },
  //     itemStyle: {
  //       shadowBlur: 10,
  //       shadowOffsetX: 0,
  //       shadowColor: 'rgba(0, 0, 0, 0.5)',
  //       borderRadius: 0,
  //     },
  //     label: {
  //       color: '#333',
  //       backgroundColor: '#fff',
  //       position: undefined,
  //       show: true,
  //       fontWeight: 'normal',
  //       fontSize: 14,
  //       formatter: undefined
  //     },
  //   }
  // ]
}
const data = ref([])
// 是否显示空白页
const isEmptyData = computed(() => {
  return data.value && data.value.length > 0 ? false : true
})
const isEmptyDataFunc = (data) => {
  if (Array.isArray(data)) {
    // 如果 data 是数组，则检查数组长度是否为 0
    return data.length === 0;
  } else if (typeof data === 'object' && data !== null) {
    // 如果 data 是对象，则检查对象是否有键
    return Object.keys(data).length === 0;
  } else if (!data) {
    return true
  } else {
    // 如果 data 不是数组也不是对象，则认为它不是空的
    return false;
  }
}
/**
 *  获取数据sql,静态数据,接口数据
 */
const loadData = async (params) => {
  const dataList = props.schema.dataList;
  let array = [];
  // 使用 map 创建一个 Promise 数组
  const promises = dataList.map(async dataItem => {
    let res = await dbsourceHook.loadDataSource(dataItem, params);
    if (!isEmptyDataFunc(res)) {
      array = [...array, ...res];
    } else {
      array = []
    }
  });
  // 使用 Promise.all 等待所有 Promise 完成
  await Promise.all(promises);
  data.value = array
}
/**扇形图显示loading */
const showLoading = () => {
  if (chartMod.value) {
    chartMod.value.showLoading()
  }
}
/**扇形图隐藏loading */
const hiddenLoading = () => {
  if (chartMod.value) {
    chartMod.value.hideLoading()
  }
}

/**
 * 处理数据   a 是echart 需要参数,b schema配置项
 */
const analyseData = (objectA, objectB) => {
  Object.getOwnPropertyNames(objectB).forEach(key => {
    objectA[key] = objectB[key] || undefined
  });
  return objectA
}
/**
 * 处理Echart数据  
 */
const handleEchartData = () => {
  const config = toRaw(props.schema.echarts)
  const { series } = config
  const { color: colorItems } = toRaw(props.schema)
  const { color } = handleCreateTableData(data.value, colorItems)
  let seriesObject = analyseData(options.series, series)
  const { radiusN, radiusW, centerH, centerV, startAngle, endAngle, padAngle, selectedMode, clockwise, selectedOffset } = seriesObject.pie
  const radius = [radiusN, radiusW]
  const center = [centerH + '%', centerV + '%']
  seriesObject = {
    ...seriesObject,
    data: data.value,
    radius,
    center,
    selectedMode,
    clockwise,
    selectedOffset,
    startAngle,
    endAngle,
    padAngle: padAngle || 0,
    label: {
      ...seriesObject.label,
      formatter: seriesObject.label.formatter || undefined
    }
  }
  options.series = []
  options.series.push(seriesObject)
  options.color = color || []
  // props.schema.color = options.color
  // props.schema.echarts.series.data = data.value
  return options
}
/**
 * 处理数据并渲染图表   
 * @param {Object} options 图表配置项
 * isLoad 是否第一次加载
 * isDataChange 监测指标数据切换
 *进行防抖
 */
const handleData = debounce(async (isLoad = true, isDataChange = false, params = {}) => {
  showLoading()
  if (isLoad === true) {
    await loadData(params)
  }
  if (data.value && data.value.length > 0) {
    // 处理指标切换
    const { dataList } = props.schema
    if (isDataChange) {
      const { list } = handlePieData(dataList, data.value)
      data.value = list
    }
    // 存储数据集
    dbSourceStore.setDbSourceDic(props.schema.id, data.value)
    const schema = toRaw(props.schema.echarts)
    options = analyseData(options, schema)
    const config = handleEchartData()
    chartMod.value?.setOption(config)
    props.schema.color = options.color
    hiddenLoading()
  } else {
    // 存储数据集
    dbSourceStore.setDbSourceDic(props.schema.id, [])
    hiddenLoading()
  }
}, 300);
/**
 * 初始化图表
 */
const initChart = async () => {
  if (chartMod.value) chartMod.value.dispose()
  if (chartRef.value) {
    chartMod.value = echarts.init(chartRef.value)
    handleData(true, true)
    if (!props.design) { // 设计模式下不能点击
      handlePieClick()
    }
  }
}
/**
 * 监听点击事件 
 */
const handlePieClick = () => {
  chartMod.value.on('click', function (params) {
    const { dataIndex } = params
    const { pathList, onClick } = props.schema
    if (pathList && pathList.length > 0) {
      const { path, params: pathParams } = pathList[dataIndex]
      const routeParams = handlePiePath(pathParams)
      onJumpToMenu(path, routeParams)
    } else {
      if (isEmpty(onClick)) return
      eventFuncHook.onClick(params, {
        otherData: { data: data.value }
      })
    }
  });
}
/**
 * 监听跳转路径
 * @param {String} path 路由路径
 *   @param {Object} routeParams 跳转额外路由参数
 */
const onJumpToMenu = (path, routeParams) => {
  if (props.design) return
  const route = tagsViewRoutes.find(v => v.path === path)
  if (!route) return
  const { name, redirect, query, meta } = route;
  if (meta?.isLink && !meta?.isIframe) {
    window.open(meta?.isLink)
  } else if (redirect) {
    router.push(redirect)
  } else {
    router.push({ name, query: { ...query, ...routeParams } })
  }
}
/**
 * 重新渲染图表
 */
const renderChart = () => {
  chartMod.value = null
  nextTick(() => {
    setTimeout(() => {
      initChart()
    }, 220);
  })
}
watch(
  () => props.schema.dataList,
  (nv, ov) => {
    if (!chartMod.value) return
    handleData(true, true)
  },
  { deep: true, immediate: false }
)
// 去除dataList,onClick属性 
const otherSchemaProps = computed(() => {
  return omit(props.schema, ['color', 'dataList', 'onClick']);
});
// 监听其他属性
watch(
  otherSchemaProps,
  (newValue, oldValue) => {
    // 在这里处理其他属性的变化
    handleData(false, false);
  },
  { deep: true, immediate: false }
);
/**
 * 
 * @param params  数组
 * 对外暴露筛选方法
 */
const reloadData = async (params) => {
  handleData(true, true, params)
}
onMounted(() => {
  emits('mounted')
  renderChart()
})
defineExpose({
  reloadData
})
</script>
<style lang="scss" scoped>
@use '@hp/panels/chart.scss' as *;
</style>